package com.trade.dao.impl;

import com.trade.dao.*;
import com.trade.dao.listener.*;
import com.trade.data.*;
import com.trade.data.type.*;
import java.util.*;
import java.util.zip.*;
import java.text.*;
import com.trade.data.calculation.*;

import org.hibernate.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.text.*;

import java.io.*;
import org.json.*;

import org.drools.logger.KnowledgeRuntimeLogger;
import org.drools.logger.KnowledgeRuntimeLoggerFactory;
import org.drools.event.rule.DebugWorkingMemoryEventListener;
import org.drools.event.rule.DebugAgendaEventListener;
import org.drools.runtime.StatefulKnowledgeSession;
import org.drools.runtime.rule.WorkingMemoryEntryPoint;
import org.drools.runtime.rule.QueryResults;
import org.drools.runtime.rule.QueryResultsRow;
import org.drools.runtime.process.ProcessInstance;

import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;


public class DroolFlowDAO extends BaseDAO implements IDroolFlowDAO {

	private Session session = null;

	private ILivePriceDAO livePriceDAO;

	//Drools Class
	private StatefulKnowledgeSession statefulKnowledgeSession;
	WorkingMemoryEntryPoint entryPoint3Sec = null;
	WorkingMemoryEntryPoint entryPoint2Min = null;
	WorkingMemoryEntryPoint entryPoint5Min = null;
	WorkingMemoryEntryPoint entryPoint30Min = null;
	WorkingMemoryEntryPoint entryPoint1Year = null;
	WorkingMemoryEntryPoint entryPointWeekly = null;

	public DroolFlowDAO() {

	}


	public void setStatefulKnowledgeSession(StatefulKnowledgeSession statefulKnowledgeSession)
	{
		this.statefulKnowledgeSession = statefulKnowledgeSession;
	}

	public void setLivePriceDAO( ILivePriceDAO livePriceDAO){
		this.livePriceDAO = livePriceDAO;
	}


	public void init(){
		//Drools
		this.entryPoint3Sec = statefulKnowledgeSession.getWorkingMemoryEntryPoint( "Stream3Sec" );
		this.entryPoint2Min = statefulKnowledgeSession.getWorkingMemoryEntryPoint( "Stream2Min" );
		this.entryPoint5Min = statefulKnowledgeSession.getWorkingMemoryEntryPoint( "Stream5Min" );
		this.entryPoint30Min = statefulKnowledgeSession.getWorkingMemoryEntryPoint( "Stream30Min" );
		this.entryPoint1Year = statefulKnowledgeSession.getWorkingMemoryEntryPoint( "Stream1Year" );
		this.entryPointWeekly = statefulKnowledgeSession.getWorkingMemoryEntryPoint( "StreamWeekly" );

		statefulKnowledgeSession.setGlobal("droolFlowDAO",this);

		//statefulKnowledgeSession.addEventListener( new DebugAgendaEventListener() );
		//statefulKnowledgeSession.addEventListener( new DebugWorkingMemoryEventListener() );

	}


	/**
	* This method used to add object in Drools Working memory.
	*/
	public synchronized void insertObject(Object object, IntervalTimeTypes intervalTimeTypes)throws Exception{

		if( IntervalTimeTypes.T3_SEC.getId() == intervalTimeTypes.getId()){
			this.entryPoint3Sec.insert(object);
		}
		else if( IntervalTimeTypes.T2_MIN.getId() == intervalTimeTypes.getId()){
			this.entryPoint2Min.insert(object);
		}
		else if( IntervalTimeTypes.T5_MIN.getId() == intervalTimeTypes.getId()){
			this.entryPoint5Min.insert(object);
		}
		else if( IntervalTimeTypes.T30_MIN.getId() == intervalTimeTypes.getId()){
			this.entryPoint30Min.insert(object);
		}
		else if( IntervalTimeTypes.T1_YEAR.getId() == intervalTimeTypes.getId()){
			this.entryPoint1Year.insert(object);
		}
		else if( IntervalTimeTypes.TWEEK_DAY.getId() == intervalTimeTypes.getId()){
			this.entryPointWeekly.insert(object);
		}
	}

	/**
	* This method used to add object in Drools Working memory.
	*/
	public synchronized void insertObject(Object object)throws Exception{
		if( object != null){
			statefulKnowledgeSession.insert( object );
		}

	}


	public synchronized ProcessInstance startProcess(String processName){
		return statefulKnowledgeSession.startProcess(processName);
	}


	/**
	* This method start trade calculation process and signal generation
	*/
	public synchronized ProcessInstance startTradeFlowProcess(ProcessFilterVO filterVO){
		Map<String,Object> map =  new HashMap<String,Object>();

		map.put("symbol", filterVO.getSymbol() != null ? filterVO.getSymbol() : "NULL" );
		map.put("intervalTimeTypes", filterVO.getIntervalTimeTypes() != null ? filterVO.getIntervalTimeTypes() : null );
		map.put("ticker", filterVO.getHistoricalDataVO());

		ProcessInstance processInstance = null ;
		if( filterVO.getIntervalTimeTypes() != null && IntervalTimeTypes.T3_SEC.getId() == filterVO.getIntervalTimeTypes().getId()){
			processInstance = statefulKnowledgeSession.startProcess("com.trade.data.ruleflow.3sec", map);
		}
		else{
			processInstance = statefulKnowledgeSession.startProcess("com.trade.data.ruleflow", map);
		}
		return processInstance;
	}


	public synchronized void fireAllRules(){
		statefulKnowledgeSession.fireAllRules();
	}




	public synchronized List<MovingAverageValuesVO> getMovingAverageValues(Object objects[] , IntervalTimeTypes intervalTimeTypes){
		String query = getQueryName( "getAll2MINMovingAverageValues" , intervalTimeTypes);

		List<MovingAverageValuesVO> obj = new ArrayList<MovingAverageValuesVO>();

		QueryResults results =	statefulKnowledgeSession.getQueryResults( query , objects );
		for ( QueryResultsRow row : results ) {
			obj.add((MovingAverageValuesVO)row.get( "object" ));
		}

		return obj;
	}


	public synchronized List<EquityIntradayDataVO> getEquityIntradayData(Object objects[] , IntervalTimeTypes intervalTimeTypes){

		String query = getQueryName( "getAll2MINEquityIntradayValues" , intervalTimeTypes);

		List<EquityIntradayDataVO> obj = new ArrayList<EquityIntradayDataVO>();

		QueryResults results =	statefulKnowledgeSession.getQueryResults( query , objects );
		for ( QueryResultsRow row : results ) {
			obj.add((EquityIntradayDataVO)row.get( "object" ));
		}

		return obj;
	}

	public synchronized Double getRSIAverageGain(Object objects[] , IntervalTimeTypes intervalTimeTypes){

		String query = getQueryName( "getAll2MINRSIAverageGain" , intervalTimeTypes);

		QueryResults results =	statefulKnowledgeSession.getQueryResults( query, objects );
		for ( QueryResultsRow row : results ) {
			return  (Double)row.get( "object" );
		}

		return 0.0;
	}

	public synchronized Double getRSIAverageLoss(Object objects[] , IntervalTimeTypes intervalTimeTypes){

		String query = getQueryName( "getAll2MINRSIAverageLoss" , intervalTimeTypes);

		QueryResults results =	statefulKnowledgeSession.getQueryResults( query , objects );
		for ( QueryResultsRow row : results ) {
			return (Double)row.get( "object" );
		}

		return 0.0;
	}


	public synchronized List<RSIValuesVO> getRSIValues(Object objects[] , IntervalTimeTypes intervalTimeTypes){

		String query = getQueryName( "getAll2MINRSIIntradayValues" , intervalTimeTypes);

		List<RSIValuesVO> obj = new ArrayList<RSIValuesVO>();

		QueryResults results =	statefulKnowledgeSession.getQueryResults( query , objects );
		for ( QueryResultsRow row : results ) {
			obj.add((RSIValuesVO)row.get( "object" ));
		}

		return obj;
	}

	public synchronized List<CCIValuesVO> getCCIValues(Object objects[] , IntervalTimeTypes intervalTimeTypes){

		String query = getQueryName( "getAll2MINCCIIntradayValues" , intervalTimeTypes);

		List<CCIValuesVO> obj = new ArrayList<CCIValuesVO>();

		QueryResults results =	statefulKnowledgeSession.getQueryResults( query , objects );
		for ( QueryResultsRow row : results ) {
			obj.add((CCIValuesVO)row.get( "object" ));
		}

		return obj;
	}


	public synchronized Double getMACDAverage(Object objects[] , IntervalTimeTypes intervalTimeTypes){

		String query = getQueryName( "getAll2MINMACDAverage" , intervalTimeTypes);

		QueryResults results =	statefulKnowledgeSession.getQueryResults( query , objects );
		for ( QueryResultsRow row : results ) {
			return (Double)row.get( "object" );
		}

		return 0.0;
	}


	public synchronized List<MACDValuesVO> getMACDValues(Object objects[] , IntervalTimeTypes intervalTimeTypes){

		String query = getQueryName( "getAll2MINMACDValues" , intervalTimeTypes);

		List<MACDValuesVO> obj = new ArrayList<MACDValuesVO>();

		QueryResults results =	statefulKnowledgeSession.getQueryResults( query , objects );
		for ( QueryResultsRow row : results ) {
			obj.add((MACDValuesVO)row.get( "object" ));
		}

		return obj;
	}


	public synchronized List<BollingerBandValuesVO> getBollingerBandValues(Object objects[] , IntervalTimeTypes intervalTimeTypes){

		String query = getQueryName( "getAll2MINBollingerBandValues" , intervalTimeTypes);

		List<BollingerBandValuesVO> obj = new ArrayList<BollingerBandValuesVO>();

		QueryResults results =	statefulKnowledgeSession.getQueryResults( query , objects );
		for ( QueryResultsRow row : results ) {
			obj.add((BollingerBandValuesVO)row.get( "object" ));
		}

		return obj;
	}



	public synchronized List<StochasticOscillatorVO> getStochasticOscillatorValues(Object objects[] , IntervalTimeTypes intervalTimeTypes){

		String query = getQueryName( "getAll2MINStochasticOscillatorValues" , intervalTimeTypes);

		List<StochasticOscillatorVO> obj = new ArrayList<StochasticOscillatorVO>();

		QueryResults results =	statefulKnowledgeSession.getQueryResults( query , objects );
		for ( QueryResultsRow row : results ) {
			obj.add((StochasticOscillatorVO)row.get( "object" ));
		}

		return obj;
	}


	public String getQueryName(String query , IntervalTimeTypes intervalTimeTypes){

		if( intervalTimeTypes == IntervalTimeTypes.T2_MIN ){
			query = query.replaceAll("2MIN" , IntervalTimeTypes.T2_MIN.getName() );
		}
		else if( intervalTimeTypes == IntervalTimeTypes.T5_MIN ){
			query = query.replaceAll("2MIN" , IntervalTimeTypes.T5_MIN.getName() );
		}
		else if( intervalTimeTypes == IntervalTimeTypes.T30_MIN ){
			query = query.replaceAll("2MIN" , IntervalTimeTypes.T30_MIN.getName() );
		}
		else if( intervalTimeTypes == IntervalTimeTypes.T1_YEAR ){
			query = query.replaceAll("2MIN" , IntervalTimeTypes.T1_YEAR.getName() );
		}
		else if( intervalTimeTypes == IntervalTimeTypes.TWEEK_DAY ){
			query = query.replaceAll("2MIN" , IntervalTimeTypes.TWEEK_DAY.getName() );
		}

		//System.out.println("Query "+query + " , type= " +intervalTimeTypes);

		return query;

	}


}